package com.xhwl.logistics.service.business;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.pojo.cent.sdata.Account;
import com.xhwl.logistics.bo.VehicleCarBO;
import com.xhwl.logistics.bo.VehicleParkingLotSecondBO;
import com.xhwl.logistics.bo.cent.ProjectBO;
import com.xhwl.logistics.bo.cent.VehicleIntegratedConfigBO;
import com.xhwl.logistics.bo.input.PageBO;
import com.xhwl.logistics.bo.input.QueryVehicleCarBO;
import com.xhwl.logistics.bo.manipulate.CreateVehicleCarBO;
import com.xhwl.logistics.bo.manipulate.DeleteVehicleCarBO;
import com.xhwl.logistics.bo.manipulate.UpdateVehicleCarBO;
import com.xhwl.logistics.converter.ToPage;
import com.xhwl.logistics.converter.mapstruct.VehicleCarSecondConverter;
import com.xhwl.logistics.converter.mapstruct.VehicleRelationCarToCardConverter;
import com.xhwl.logistics.entity.VehicleCar;
import com.xhwl.logistics.entity.VehicleRelationCarToCard;
import com.xhwl.logistics.enums.VehicleParkingLotCarAuthEnum;
import com.xhwl.logistics.po.VehicleCarPO;
import com.xhwl.logistics.service.cent.QueryDeviceService;
import com.xhwl.logistics.service.cent.QueryProjectService;
import com.xhwl.logistics.service.impl.VehicleCarServiceImpl;
import com.xhwl.logistics.service.impl.VehicleParkingLotServiceImpl;
import com.xhwl.logistics.service.impl.VehicleRelationCarToCardServiceImpl;
import com.xhwl.logistics.strategy.IVehicleParkingLotCarAuthHandler;
import com.xhwl.logistics.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

//@Service
@Slf4j
public class VehicleCarBusinessService {

    @Autowired
    private VehicleCarSecondConverter vehicleCarSecondConverter;

    @Autowired
    private VehicleRelationCarToCardConverter vehicleRelationCarToCardConverter;


    @Autowired
    private VehicleCarServiceImpl vehicleCarService;

    @Autowired
    private VehicleRelationCarToCardServiceImpl vehicleRelationCarToCardService;


    @Autowired
    private VehicleParkingLotServiceImpl vehicleParkingLotService;

    @Autowired
    private QueryProjectService queryProjectService;

    @Autowired
    private QueryDeviceService queryDeviceService;


    @Autowired
    private ToPage toPage;

    public IPage<VehicleCarBO> queryCars(QueryVehicleCarBO queryVehicleCarBO, PageBO pageBO) {
        /**
         * 对前端传的%和_进行处理
         */
        queryVehicleCarBO.setPlateNumber(EscapeCharacter.escape(queryVehicleCarBO.getPlateNumber()));
        IPage<VehicleCarPO> vehicleCarPOIPage = vehicleCarService.queryCars(pageBO.toPage(), queryVehicleCarBO);

        List<VehicleCarBO> vehicleCarBOList = vehicleCarSecondConverter.vehicleCarPOList2VehicleCarBOList(vehicleCarPOIPage.getRecords());
        return toPage.toPage(vehicleCarPOIPage, vehicleCarBOList);
    }

    public VehicleCarBO detailCar(Integer id) {
        VehicleCarPO vehicleCarPO = vehicleCarService.getCar(id).orElseThrow(() -> new BusinessException("根据id无法找到车辆"));
        return vehicleCarSecondConverter.toVehicleCarBO(vehicleCarPO);
    }

    @Transactional(rollbackFor = {Exception.class})
    public void addCar(CreateVehicleCarBO createVehicleCarBO) {
        Integer projectId = createVehicleCarBO.getProjectId();

        ProjectBO projectBO = queryProjectService.queryProject(projectId);
        VehicleParkingLotSecondBO vehicleParkingLotSecondBO = vehicleParkingLotService.queryParkingLot(projectId, createVehicleCarBO.getParkingLotName());
        createVehicleCarBO.setParkingLotName(vehicleParkingLotSecondBO.getParkingLotName());

        VehicleCar vehicleCar = vehicleCarSecondConverter.toVehicleCar(createVehicleCarBO, projectBO.getProjectName(), vehicleParkingLotSecondBO.getId());
        vehicleCarService.save(vehicleCar);

        Integer cardId = createVehicleCarBO.getCardId();
        if (Objects.nonNull(cardId) && cardId!=0) {
            Integer carId = vehicleCar.getId();
            VehicleRelationCarToCard vehicleRelationCarToCard = vehicleRelationCarToCardConverter.toVehicleRelationCarToCard(carId, createVehicleCarBO, projectBO.getProjectName(), vehicleParkingLotSecondBO.getId());
            vehicleRelationCarToCardService.save(vehicleRelationCarToCard);
        }
    }

    @Transactional(rollbackFor = {Exception.class})
    public void deleteCar(DeleteVehicleCarBO deleteVehicleCarBO) {
        vehicleCarService.deleteCar(deleteVehicleCarBO);

        vehicleRelationCarToCardService.queryRelation(deleteVehicleCarBO.getId())
                .ifPresent(vehicleRelationCarToCard -> {
                    Integer id = vehicleRelationCarToCard.getId();
                    Integer deleterAccountId = deleteVehicleCarBO.getDeleterAccountId();
                    String deleterAccountName = deleteVehicleCarBO.getDeleterAccountName();
                    vehicleRelationCarToCardService.deleteRelation(id, deleterAccountId, deleterAccountName);
                });
    }

    public void deleteCars(List<Integer> idList) {
        vehicleCarService.deleteCars(idList);

        List<Integer> relationIdList = vehicleRelationCarToCardService.queryRelations(idList).stream().map(VehicleRelationCarToCard::getId).collect(Collectors.toList());
        if (!relationIdList.isEmpty()) {
            vehicleRelationCarToCardService.deleteRelations(relationIdList);
        }
    }

    @Transactional(rollbackFor = {Exception.class})
    public void updateCar(UpdateVehicleCarBO updateVehicleCarBO) {
        VehicleCar vehicleCar = vehicleCarSecondConverter.updateVehicleCarBO2VehicleCar(updateVehicleCarBO);
        vehicleCarService.updateById(vehicleCar);
    }

    /**
     * 月卡车缴费续期
     */
    public void chargeMonthCar(HttpServletRequest request, HttpServletResponse response, Account account){
        JSONObject reqDataObject = JSONObject.parseObject(ServletUtils.onGettingRequestBody(request));
        Integer projectId = ServletUtils.getValidateParamInt(reqDataObject, "projectId", "项目id为空");
        Integer carId = ServletUtils.getValidateParamInt(reqDataObject, "id", "车id为空");
        Date endTime = ServletUtils.getValidateParamDate(reqDataObject, "endTime", "续期的结束时间为空");

        List<VehicleRelationCarToCard> vehicleRelationCarToCards = vehicleRelationCarToCardService.list(conditionForRelationByProjectIdAndCarId(projectId, carId));
        if(vehicleRelationCarToCards.isEmpty()){
            throw new BusinessException("该条车辆信息与车卡信息被删除了，故无法更新");
        }

        VehicleIntegratedConfigBO vehicleIntegratedConfigBO = queryDeviceService.queryIntegratedConfigFromProjectId(projectId);
        IVehicleParkingLotCarAuthHandler vehicleParkingLotCarAuthHandler = SpringContextUtils.getApplicationContext().getBean(
                VehicleParkingLotCarAuthEnum.toVehicleParkingLotCarAuthEnum(vehicleIntegratedConfigBO.getVehicleSystemInfoBO().getProductId()).getHandlerName(),
                IVehicleParkingLotCarAuthHandler.class
        );

        vehicleParkingLotCarAuthHandler.chargeMonthCar(vehicleIntegratedConfigBO, reqDataObject);

        VehicleRelationCarToCard vehicleRelationCarToCard = vehicleRelationCarToCards.get(0);
        vehicleRelationCarToCard.setValidEndTime(endTime);
        if(account != null){
            vehicleRelationCarToCard.setEditorAccountId(account.getId());
            vehicleRelationCarToCard.setEditorAccountName(account.getName());
        }
        vehicleRelationCarToCardService.updateById(vehicleRelationCarToCard);
        ServletUtils.RespToSuccess(response);
    }

    /**
     * 通过项目id和车id查询车与车卡的联系信息
     */
    private Wrapper<VehicleRelationCarToCard> conditionForRelationByProjectIdAndCarId(Integer projectId, Integer carId){
        return new LambdaQueryWrapper<VehicleRelationCarToCard>()
                .eq(VehicleRelationCarToCard::getProjectId, projectId)
                .eq(VehicleRelationCarToCard::getCarId, carId);
    }

}
